import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hack_a_tone/bloc/tracker.dart';

typedef Timeline = Map<String, List<DateTimeRange>>;

sealed class TimerState {
  const TimerState({required this.apps, this.currentApp});
  final String? currentApp;
  final Timeline apps;

}

final class TimerRuning extends TimerState {
  const TimerRuning({required super.apps, super.currentApp});

  @override
  String toString() => 'TimerRuning { duration: $apps }';
}

final class TimerStopped extends TimerState {
  const TimerStopped({required super.apps, super.currentApp});

  @override
  String toString() => 'TimerStopped { duration: $apps }';
}

sealed class ActiveWindowKeeperEvent {}

final class _FetchActiveWindow extends ActiveWindowKeeperEvent {
  _FetchActiveWindow({required this.name});
  String name;
}

final class StartTrackingActiveWindow extends ActiveWindowKeeperEvent {}

final class StopTrackingActiveWindow extends ActiveWindowKeeperEvent {}

class ActiveWindowKeeperBloc extends Bloc<ActiveWindowKeeperEvent, TimerState> {
  ActiveWindowKeeperBloc({required Ticker ticker})
      : _ticker = ticker,
        super(const TimerStopped(apps: {})) {
    on<StartTrackingActiveWindow>(_onStarted);
    on<StopTrackingActiveWindow>(_onPaused);
    on<_FetchActiveWindow>(_onTicked);
  }

  final Ticker _ticker;

  StreamSubscription<String>? _tickerSubscription;

  @override
  Future<void> close() {
    _tickerSubscription?.cancel();
    return super.close();
  }

  void _onStarted(StartTrackingActiveWindow event, Emitter<TimerState> emit) {
    emit(TimerRuning(apps: state.apps));
    _tickerSubscription?.cancel();
    _tickerSubscription =
        _ticker.tick().listen((app) => add(_FetchActiveWindow(name: app)));
  }

  void _onPaused(StopTrackingActiveWindow event, Emitter<TimerState> emit) {
    if (state is TimerRuning) {
      _tickerSubscription?.cancel();
      emit(TimerStopped(apps: state.apps));
    }
  }

  void _onTicked(_FetchActiveWindow event, Emitter<TimerState> emit) {
    Timeline st = {};
    st.addAll(state.apps);
    String? currentApp = state.currentApp;
    if (currentApp == event.name) {
      var lastDelay = st[currentApp]!.last;
      st[event.name]!.last = DateTimeRange(
          start: lastDelay.start,
          end: lastDelay.end.add(const Duration(seconds: 1)));
    } else {
      if (currentApp != null) {
        var lastDelay = st[currentApp]!.last;
        st[currentApp]!.last = DateTimeRange(
            start: lastDelay.start,
            end: lastDelay.end.add(const Duration(seconds: 1)));
      }
      currentApp = event.name;
      st[currentApp] = st[currentApp] ?? [];
      st[currentApp]!
          .add(DateTimeRange(start: DateTime.now(), end: DateTime.now()));
    }
    emit(TimerRuning(apps: st, currentApp: currentApp));
  }
}
